Ana içeriğe geç
  1. 100 Günde SwiftUI Notları/

52.Gün - SwiftUI Proje 10 (Cupcake Corner) Challange ve Çözümleri

Umarım bu proje size bildiğiniz becerileri (SwiftUI Picker, Stepper ve Navigation) nasıl kullanacağınızı ve bunları kullanıcının tüm verilerini bir sunucuya gönderen ve yanıtı işleyen bit uygulama haline nasıl getireceğimizi göstermiştir.

Henüz bunun farkında olmayabilirsiniz, ancak projede öğrendiğiniz beceriler iOS geliştiricilerinin büyük çoğunluğu için önemli becerilerdir: kullanıcı verilerini almak, bir sunucuya göndermek ve yanıtı işlemek muhtemelen var olan önemsiz olmayan uygulamaların yarısını oluşturur. Evet, hangi verilerin gönderileceği ve kullanıcı arayüzünü güncellemek için nasıl kullanılacağı büyük ölçüde değişir, ancak kavramlar aynıdır.

Meydan Okuma (Challange) #

Bu uygulamayı ilerletmek için denememiz gereken 3 yol;

  1. Adres alanlarımız şu anda sadece boşluk olsa bile herhangi bir şey içeriyorsa geçerli kabul ediliyor. Salt boşluk içeren bir string’in geçersiz olduğundan emin olmak için doğrulamayı iyileştirin.
  2. placeOrder() çağrımız başarısız olursa - örneğin internet bağlantısı yoksa - kullanıcı için bilgilendirici bir uyarı gösterin. Bunu test etmek için, kodunuzdaki  request.httpMethod = "POST" satırını yorum haline getirebilirsiniz, bu request’i başarısız olmaya zorlayacaktır.
  3. Daha zorlu bir görev için Order sınıfını güncellemeyi deneyin, böylece kullanıcının teslimat adresi gibi verileri UserDeafults’a kaydedebiliriz. Bu biraz düşünmeyi gerektirir, çünkü @AppStorage burada çalışmaz ve getter ve setter’ların Codable desteğinde sorunlara neden olduğunu göreceksiniz. Bir orta yol bulabilir misiniz?

Challange Çözümleri #

  1. Bu problemi çözmek için String üzerinde bir extension yazabiliriz. Bu extension’da allSatisfy() methodunu kullanarak String’in her bir elemanı üzerinde kontrol yapabiliriz. String’in her bir elemanı Character olduğundan, Character üzerinde tanımlı bir method olan .isWhitespace ‘i kullanabiliriz. Aşağıdaki kod sayesinde String’e yeni bir method ekleyeceğiz ve bu method sayesinde string tamamen boşluktan (whitespace) oluşuyorsa true değerini geri döneceğiz.

    extension String {
        var isBlank: Bool {
            allSatisfy({$0.isWhitespace})
        }
    }
    

    Yukarıdaki kodu yazdıktan sonra, Order sınıfımızda var hasValidAddress: Bool { kısmını şu şekilde değiştirebiliriz;

    if name.isEmpty || name.isBlank || streetAddress.isEmpty || streetAddress.isBlank || city.isEmpty || city.isBlank || zip.isEmpty || zip.isBlank {
    
  2. İnternet bağlantısı ile ilgili bir problem olduğunda bir uyarı göstermek için, öncelikli olarak CheckoutView’da bir değişken oluşturalım;

    @State private var showingNoInternet = false
    

    Ardından daha önce oluşturduğumuz alert’in altında bir tane daha oluşturalım;

    .alert("Oops!", isPresented: $showingNoInternet) {
         Button("OK", role: .cancel) { }
     } message: {
         Text("Please check your internet connection.")
     }
    

    Son olarak placeOrder() methodumuzda bulunan catch bloğuna aşağıdaki kodu ekleyelim;

    showingNoInternet = true
    

    no internet alert

  3. Bu problemin çözümü için öncelikli olarak verileri UserDefaults’a nerede veri yazacağımıza karar vermeliyiz. Bunun için en uygun yer AddressView’da CheckoutView’ı push ettiğimiz yer olan NavigationLink bölümüdür. Bu sebeple kodu şu şekilde değiştirin;

    Section{
        NavigationLink("Check out") {
            CheckoutView(order: order)
                .onAppear {
                    let addressItems = [order.name, order.streetAddress, order.city, order.zip]
                    if let encoded = try? JSONEncoder().encode(addressItems) {
                        UserDefaults.standard.set(encoded, forKey: "addressItems")
                        print("Address Items kaydedildi.")
                    }
                }
        } //NavigationLink
    } //Section-2
    

    Şimdiki sorun UserDefaults’a kaydettiğimiz verileri nerede okuyacağımızdır. Bunun için en uygun yer Order sınıfının init() fonksiyonudur. Bu fonksiyonda UserDefaults’u okuruz eğer kaydedilmiş veri varsa bu verileri sınıf nesnesi yaratılırken ilgili değerlere atarız, eğer veri yoksa boş string atarız. Bunun için Order sınıfında şu değişkenleri tanımladığımız yeri değiştirin;

    var name: String
    var streetAddress: String
    var city: String
    var zip: String
    

    Ardından aşağıdaki gibi init() fonksiyonunu yazın;

    init() {
        if let dataName = UserDefaults.standard.data(forKey: "addressItems") {
            if let decodedName = try? JSONDecoder().decode([String].self, from: dataName) {
                name = decodedName[0]
                streetAddress = decodedName[1]
                city = decodedName[2]
                zip = decodedName[3]
                return
            }
        }
    
        name = ""
        streetAddress = ""
        city = ""
        zip = ""
    }
    

Tamamlanmış projeye aşıdaki Github linkinden ulaşabilirsiniz;


Bu yazıyı İngilizce olarak da okuyabilirsiniz.
You can also read this article in English.

Bu yazı, SwiftUI Day 52 adresinde bulunan yazılardan kendim için aldığım notları içermektedir. Orjinal dersi takip etmek için lütfen bağlantıya tıklayın.